package ae.pcfc.etks.online.itworx.ehs.web.web.controller;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.ws.WebServiceException;

import ae.pcfc.etks.online.common.delegate.UserDelegate;
import ae.pcfc.etks.online.common.vo.UserDetailVO;
import ae.pcfc.etks.online.itworx.ehs.web.common.exception.helper.ExceptionHandlerHelper;
import ae.pcfc.etks.online.itworx.ehs.web.constants.GlobalConstants;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.EHSDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.FNPDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.IMSDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.delegate.WorkflowDelegate;
import ae.pcfc.etks.online.itworx.ehs.web.entity.FNPDetails;
import ae.pcfc.etks.online.itworx.ehs.web.entity.OFCRequest;
import ae.pcfc.etks.online.itworx.ehs.web.entity.OFCRequestHistory;
import ae.pcfc.etks.online.itworx.ehs.web.entity.Request;
import ae.pcfc.etks.online.itworx.ehs.web.enums.AmendmentType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.FNPRequestStatus;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestAction;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestField;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestStatus;
import ae.pcfc.etks.online.itworx.ehs.web.enums.RequestType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.UserType;
import ae.pcfc.etks.online.itworx.ehs.web.enums.WorkflowDataFields;
import ae.pcfc.etks.online.itworx.ehs.web.exception.CommunicationException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.FNPServiceExpcetion;
import ae.pcfc.etks.online.itworx.ehs.web.exception.IMSException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.InvalidInputException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.SystemException;
import ae.pcfc.etks.online.itworx.ehs.web.exception.WorkFlowException;
import ae.pcfc.etks.online.itworx.ehs.web.messaging.JmsMessageProducer;
import ae.pcfc.etks.online.itworx.ehs.web.model.FNP;
import ae.pcfc.etks.online.itworx.ehs.web.model.OFCRequestCreation;
import ae.pcfc.etks.online.itworx.ehs.web.model.PaymentAdvice;
import ae.pcfc.etks.online.itworx.ehs.web.model.RequestSearchCriteria;
import ae.pcfc.etks.online.itworx.ehs.web.model.TrakheesRequestParameter;
import ae.pcfc.etks.online.itworx.ehs.web.util.MailUtility;
import ae.pcfc.etks.online.itworx.ehs.web.util.UtilCommon;

@Controller
@RequestMapping("/officer")
@SessionAttributes(value = GlobalConstants.OFC_REQUEST_MODEL)
public class Officer {
	private MailUtility mailUtility;
	private WorkflowDelegate workflowDelegate;
	private EHSDelegate ehsDelegate;
	private Validator validator;
	private FNPDelegate fnpDelegate;
	private UserDelegate tscUserDelegate;
	private IMSDelegate imsDelegate;
	private JmsMessageProducer producer;
	@SuppressWarnings("unused")
	private ResourceBundleMessageSource messageSource;
	private Map<String, String> generalMap;

	@Resource(name = "generalMap")
	public void setGeneralMap(Map<String, String> generalMap) {
		this.generalMap = generalMap;
	}
	
	/**
	 * @param messageSource
	 *            the messageSource to set
	 */
	@Resource(name = "messageSource")
	public void setMessageSource(ResourceBundleMessageSource messageSource) {
		this.messageSource = messageSource;
	}
	
	private static Logger log = LoggerFactory.getLogger(Officer.class);

	@Resource(name = "validator")
	public void setValidator(Validator validator) {
		this.validator = validator;
	}

	@InitBinder
	public void initBinder(WebDataBinder binder, Locale locale) {
		binder.setValidator(validator);
	}

	@Resource(name = "ehsDelegate")
	public void setEhsDelegate(EHSDelegate ehsDelegate) {
		this.ehsDelegate = ehsDelegate;
	}

	@Resource(name = "workflowDelegate")
	public void setWorkflowDelegate(WorkflowDelegate workflowDelegate) {
		this.workflowDelegate = workflowDelegate;
	}

	public MailUtility getMailUtility() {
		return mailUtility;
	}

	@Resource(name = "mailUtility")
	public void setMailUtility(MailUtility mailUtility) {
		this.mailUtility = mailUtility;
	}

	@Resource(name = "fnpDelegate")
	public void setFnpDelegate(FNPDelegate fnpDelegate) {
		this.fnpDelegate = fnpDelegate;
	}

	@Resource(name = "tscUserDelegate")
	public void setTscUserDelegate(UserDelegate tscUserDelegate) {
		this.tscUserDelegate = tscUserDelegate;
	}

	@Resource(name = "imsDelegate")
	public void setImsUserDelegate(IMSDelegate imsDelegate) {
		this.imsDelegate = imsDelegate;
	}
	
	@Resource(name = "producer")
	public void setJmsMessageProducer(JmsMessageProducer producer){
		this.producer = producer;
	}
	
	@RequestMapping(value = "/selectTksUsers.htm", method = RequestMethod.GET)
	@Transactional(readOnly = true)
	public String selectTksUsers(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {
		TrakheesRequestParameter trakheesRequestParam = new TrakheesRequestParameter();
		trakheesRequestParam.setType(type);
		trakheesRequestParam.setRequestType(type);
		model.addAttribute(GlobalConstants.TRAKHEES_REQUEST_PARAMETER,
				trakheesRequestParam);
		return "officer.selectTksUsers";
	}

	@RequestMapping(value = "/selectTksUsers.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String selectTksUsers(
			Model model,
			HttpServletRequest request,
			@ModelAttribute(value = GlobalConstants.TRAKHEES_REQUEST_PARAMETER) @Valid TrakheesRequestParameter trakheesRequestParam,
			BindingResult errors) {

		String trakheesId = UtilCommon.trim(trakheesRequestParam
				.getTrakheesId());
		trakheesRequestParam.setTrakheesId(trakheesId);
		if (UtilCommon.isEmpty(trakheesId)) {
			errors.reject("error.trakheesId.empty");
			return "officer.selectTksUsers";
		}

		List<UserDetailVO> trakheesIdUsers = tscUserDelegate
				.searchUsersByTrakheesId(trakheesId);
		if (!UtilCommon.isEmpty(trakheesRequestParam.getSortField())) {
			UtilCommon.sort(trakheesIdUsers,
					trakheesRequestParam.getSortField(),
					trakheesRequestParam.isAssending());
		}
		int pageSize = Integer.parseInt(generalMap.get("pageSize"));
		long totalPages = UtilCommon.getCollectionPagesCount(trakheesIdUsers, pageSize);
		long allUsersSize = trakheesIdUsers.size();
		List<UserDetailVO> pagedTrakheesIdUsers = UtilCommon.getCollectionPage(
				trakheesIdUsers, trakheesRequestParam.getPageNumber(), pageSize);

		trakheesRequestParam.setTotalPageNumber((int) totalPages);
		trakheesRequestParam.setTotalResultSize((int) allUsersSize);
		trakheesRequestParam.setFirstAndLastPageFlags();

		model.addAttribute(GlobalConstants.TRAKHEES_REQUEST_PARAMETER,
				trakheesRequestParam);
		model.addAttribute("trakheesIdUsers", pagedTrakheesIdUsers);
		return "officer.selectTksUsers";
	}

	@RequestMapping(value = "/listRequests.htm", method = RequestMethod.GET)
	@Transactional(readOnly = true)
	public String listRequests(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {

		/*String userId = "somaya.rayan";// should get it from session
												// when integrating with login
												// logic,but now for testing we
												// will add it here
		HttpSession session = request.getSession();
		session.setAttribute(GlobalConstants.USER_NAME_ATTRIBUTE, userId);
*/
		// session.setAttribute(GlobalConstants.TYPE_ATTRIBUTE,
		// GlobalConstants.MY_REQUESTS);
String officerId=request.getUserPrincipal().getName();

		System.out
				.println("**************** Officer controller ,listRequests, GET");
		// 1- set the default date period
		RequestSearchCriteria searchCriteria = new RequestSearchCriteria();
		Calendar today = Calendar.getInstance();
		today.setTime(new Date());
		// searchCriteria.setSubmissionDateTo(today.getTime());
		// today.add(Calendar.DATE, -7);
		// searchCriteria.setSubmissionDateFrom(today.getTime());
		searchCriteria.setPageNumber(1);

		// this attribue is added to keep track of which menu item is currently
		// selected!!!!
		searchCriteria.setType(type);

		List<Request> requests = new ArrayList<Request>();
		try {

			long allRequestsSize = workflowDelegate.getAllRequestsSize(officerId,
					true, searchCriteria);
			System.out.println("*** allRequestsSize = " + allRequestsSize
					+ " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = allRequestsSize / pageSize;
			if ((allRequestsSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) allRequestsSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setAssending(true);
			System.out.println("*** totalPages = " + totalPages + " ******");
			requests = workflowDelegate.getAllRequests(officerId, true,
					searchCriteria);
			searchCriteria.setSortField(RequestField.CreationDate.getPropertyName());
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Officer.listRequests()/GET - error while listing requests", e);
		}
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "officer.listRequests";
	}

	@RequestMapping(value = "/listRequests.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String listRequests(
			@ModelAttribute(value = GlobalConstants.REQUEST_SEARCH_CRITERIA) @Valid RequestSearchCriteria searchCriteria,
			BindingResult errors, Model model, HttpServletRequest request) {

		/*String userId = "somaya.rayan";// should get it from session
												// when integrating with login
												// logic,but now for testing we
												// will add it here
		HttpSession session = request.getSession();
		session.setAttribute(GlobalConstants.USER_NAME_ATTRIBUTE, userId);
*/
		// session.setAttribute(GlobalConstants.TYPE_ATTRIBUTE,
		// GlobalConstants.MY_REQUESTS);
String officerId=request.getUserPrincipal().getName();
		System.out
				.println("**************** Officer controller ,listRequests, POST");
		List<Request> requests = new ArrayList<Request>();
		try {
			searchCriteria = buildRequestId(searchCriteria);
			/*if (null != searchCriteria.getCreationDate()
					& null != searchCriteria.getSubmissionDate()) {
				if (!UtilCommon.dateCompare(searchCriteria.getCreationDate(),
						searchCriteria.getSubmissionDate())) {
					errors.reject("error.requestSearchCriteria.date");
				}
			}*/
			if (errors.hasErrors()) {
				return "officer.listRequests";
			}
			long allRequestsSize = workflowDelegate.getAllRequestsSize(officerId,
					true, searchCriteria);
			System.out.println("*** allRequestsSize = " + allRequestsSize
					+ " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = allRequestsSize / pageSize;
			if ((allRequestsSize % pageSize) > 0) {
				totalPages++;
			}
			System.out.println("*** totalPages = " + totalPages + " ******");
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) allRequestsSize);
			searchCriteria.setFirstAndLastPageFlags();
			requests = workflowDelegate.getAllRequests(officerId, true,
					searchCriteria);
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Officer.listRequests()/POST - error while listing requests",e);
		}

		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return "officer.listRequests";
	}

	@RequestMapping(value = "/viewDetails.htm", method = RequestMethod.POST)
	public String manipulateRequest(
			@ModelAttribute(value = GlobalConstants.OFC_REQUEST_MODEL) OFCRequestCreation ofcRequestModel,
			BindingResult errors, HttpServletRequest request,
			@RequestHeader(value = "referer", required = false) String referer) {

		//String officerId="somaya.rayan";//request.getUserPrincipal().getName(); 
                
                String officerId=request.getUserPrincipal().getName(); 

		String action = request.getParameter("action");
		try {
			if (null != action
					&& null != RequestAction.getRequestAction(action)) {
				RequestAction requestAction = RequestAction
						.getRequestAction(action);
				if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
					ofcRequestModel.setAmendmentTypes(AmendmentType.values());

			}
				if (requestAction.equals(RequestAction.Approve)) {
					if (null != ofcRequestModel.getFnpDetails()
							&& !ofcRequestModel.getFnpDetails().isEmpty()) {
						request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.edit", null, RequestContextUtils.getLocale(request)));
						String forwardedURL = null;
						
						try {
							forwardedURL = approveRequest(ofcRequestModel,officerId, request,errors);
						} catch (IMSException e) {
							ExceptionHandlerHelper.handleException(e);
						} catch (FNPServiceExpcetion e){
							ExceptionHandlerHelper.handleException(e);
						} catch (CommunicationException e){
							ExceptionHandlerHelper.handleException(e);
						}
						
						if(!errors.hasErrors())
						{
							return forwardedURL;
						}
					} else {
						errors.reject("error.officer.payment.fees.needed");
					}
				} else if (requestAction.equals(RequestAction.PaymentConfirmed)
						|| requestAction
								.equals(RequestAction.ADDITIONAL_Payment_Confirmed)) {//TODO//Change it after discussion with EZZ

					if (!confirmPayment(ofcRequestModel,officerId,request)) {
						request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("error.ofcRequestModel.payment.notConfirmed", null, RequestContextUtils.getLocale(request)));
						return "redirect:" + referer;
					}else{
						request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.edit", null, RequestContextUtils.getLocale(request)));
						return "redirect:listRequests.htm?type=myRequests";
					}

				} else if (requestAction.equals(RequestAction.ReturnForUpdate)) {
					return returnOrReject(ofcRequestModel, errors,
							RequestAction.ReturnForUpdate, referer,officerId, request);

				} else if (requestAction.equals(RequestAction.Reject)) {
					return returnOrReject(ofcRequestModel, errors,
							RequestAction.Reject, referer,officerId, request);

				} else if (requestAction
						.equals(RequestAction.ADDITIONAL_FEES_REQUIRED)) {

                                        request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.edit", null, RequestContextUtils.getLocale(request)));
					
					String forwardedURL=additionalFees(ofcRequestModel, officerId, request,errors);
					if(!errors.hasErrors())
					{
						return forwardedURL;
					}
					
				} else if (requestAction.equals(RequestAction.Close)) {
					closeRequest(ofcRequestModel, request, officerId);
					return "redirect:listRequests.htm?type=myRequests";
				}
			} else {
				errors.reject("error.officer.invalidAction");
			}
		} catch (InvalidInputException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.manipulateRequest()/POST - invalid input provided while manipulating request ("+request+")",e);
		} catch (WorkFlowException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.manipulateRequest()/POST - work flow error while manipulating request ("+request+")",e);
			ExceptionHandlerHelper.handleException(e);
		} catch (RuntimeException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.manipulateRequest()/POST - run time error while manipulating request ("+request+")",e);
		}catch (FNPServiceExpcetion e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.manipulateRequest()/POST - FNP error while manipulating request ("+request+")",e);
		} catch (CommunicationException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.manipulateRequest()/POST - error while manipulating request ("+request+")",e);
			errors.reject("error.ofcRequestModel.exception");
			return "redirect:" + referer;
		}
		return "officer.viewDetails";
	}

	@Transactional
	public void closeRequest(OFCRequestCreation ofcRequestModel,
			HttpServletRequest request, String officerId)
			throws CommunicationException, InvalidInputException,
			WorkFlowException {
		OFCRequest ofcRequest = new OFCRequest();
		workflowDelegate.getMapper().map(ofcRequestModel,
				ofcRequest);
		updateRequest(ofcRequest, RequestStatus.Closed,officerId);
		request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.edit", null, RequestContextUtils.getLocale(request)));
		boolean requestManipulated=workflowDelegate.manipulateRequest(ofcRequest, ofcRequest.getOfficerId(), true, RequestAction.Close);
		if(!requestManipulated)
		{
				WorkFlowException workflowExp=new WorkFlowException("Error happened during Request Manipulation");
				workflowExp.setErrorCode("error.workflow.unexpected");
				throw workflowExp;
		}
	}

	@Transactional
	private String additionalFees(OFCRequestCreation ofcRequestCreation,String officerId, HttpServletRequest request,BindingResult errors)
	{	
		String customerUserName = ofcRequestCreation.getUserId();
		OFCRequest ofcRequest=null;
		UserDetailVO userDetails=null;
		PaymentAdvice paymentInfo=null;
		String txnNumber=null;
		
		try
		{
			ofcRequest=new OFCRequest();
			workflowDelegate.getMapper().map(ofcRequestCreation, ofcRequest);
						
			userDetails =  tscUserDelegate.findUserDetailByUserName(customerUserName);
			
			ObjectMapper mapper = new ObjectMapper();
			FNP fnpModel=mapper.readValue(ofcRequestCreation.getFnpDetails(), FNP.class);
			
			txnNumber=UtilCommon.generateFNPTransactioNum(ofcRequestCreation.getId()+GlobalConstants.ADDITIONAL_PAYMENT_ADVICE);
			
			paymentInfo=generateFees(fnpModel,String.valueOf(ofcRequestCreation.getId()), ofcRequestCreation.getUserId(),txnNumber,userDetails);
						
			FNPDetails fnpDetails = new FNPDetails();
			fnpDetails.setPaymentNumber(paymentInfo.getPaymentAdviceNumber());
			fnpDetails.setFees((float) paymentInfo.getPaymentfees());
		
			ofcRequest.getFnpList().add(fnpDetails);
			
			
			ofcRequest.setExecuter(UserType.Officer);
			ofcRequest.setStatus(RequestStatus.Additional_Payment_Required);
			ofcRequest.setOfficerId(officerId);
			ofcRequest.setProcessingDate(new Date());

			OFCRequestHistory history = new OFCRequestHistory();
			workflowDelegate.getMapper().map(ofcRequest, history);
			ofcRequest.getOfcHistory().add(history);
			
			boolean requestManipulated=workflowDelegate.manipulateRequest(ofcRequest,officerId, true, RequestAction.ADDITIONAL_FEES_REQUIRED);
			
			if(requestManipulated){
				sendTarakheesMail(paymentInfo, ofcRequest, request);
			}
			else
			{
				WorkFlowException workflowExp=new WorkFlowException("Error happened during Request Manipulation");
				workflowExp.setErrorCode("error.workflow.unexpected");
				throw workflowExp;
			}
			
		}
		 catch (DataAccessException e){
				log.error("Officer.additionalFees() - DataAccessException going to send request to queue to be updated later",e);
			producer.generatePendingRequestMessage(ofcRequest);
errors.reject("error.request");
		}catch(FNPServiceExpcetion fnpExp)
		{
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			ExceptionHandlerHelper.handleException(fnpExp);
			errors.reject(fnpExp.getErrorCode());
		}
			catch (WorkFlowException wfExp)
			{
				request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);

				wfExp.setErrorRollbackBean(UtilCommon.prepareRollback(null,  paymentInfo.getPaymentAdviceNumber(), txnNumber, customerUserName, null));
				ExceptionHandlerHelper.handleException(wfExp);
				errors.reject(wfExp.getErrorCode());
			}
			catch (CommunicationException commExp) {
				request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
				
				commExp.setErrorRollbackBean(UtilCommon.prepareRollback(null,  paymentInfo.getPaymentAdviceNumber(), txnNumber, customerUserName, null));
				ExceptionHandlerHelper.handleException(commExp);
				errors.reject(commExp.getErrorCode());
			}
			catch (WebServiceException e){
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.additionalFees() - WebServiceException error occurred while approve request",e);
		} catch (Exception e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.additionalFees() - Exception error occurred while approve request",e);
		}
		
		return "redirect:listRequests.htm?type=myRequests";
	}
	
	@Transactional
	private String approveRequest(OFCRequestCreation ofcRequestCreation,String officerId, HttpServletRequest request,BindingResult errors) throws FNPServiceExpcetion, IMSException, CommunicationException{
		
		String imsLogId = null;
		String customerUserName = ofcRequestCreation.getUserId();
		OFCRequest ofcRequest=null;
		UserDetailVO userDetails=null;
		PaymentAdvice paymentInfo=null;
		String txnNumber=null;
		
		try {
			
			ofcRequest=new OFCRequest();
			workflowDelegate.getMapper().map(ofcRequestCreation, ofcRequest);
			
			userDetails =  tscUserDelegate.findUserDetailByUserName(customerUserName);
			
			
			ObjectMapper mapper = new ObjectMapper();
			FNP fnpModel=mapper.readValue(ofcRequestCreation.getFnpDetails(), FNP.class);

		
			txnNumber=UtilCommon.generateFNPTransactioNum(ofcRequestCreation.getId()+GlobalConstants.INITIAL_PAYMENT_ADVICE);
			
			paymentInfo=generateFees(fnpModel,String.valueOf(ofcRequestCreation.getId()), ofcRequestCreation.getUserId(),txnNumber,userDetails);
			
			FNPDetails fnpDetails = new FNPDetails();
			fnpDetails.setPaymentNumber(paymentInfo.getPaymentAdviceNumber());
			
			fnpDetails.setFees((float) paymentInfo.getPaymentfees());

			ofcRequest.getFnpList().add(fnpDetails);

			if(ofcRequestCreation.getType().equals(RequestType.New)||ofcRequestCreation.getType().equals(RequestType.Amendment))
			{
			//TODO : Officer and Client IDs
				imsLogId = imsDelegate.createIMPSRecord(GlobalConstants.INSPECTION_CODE, ofcRequestCreation.getType().toString().toUpperCase(), ofcRequestCreation.getBusinessUnit(),ofcRequestCreation.getTrakheesId(), officerId);
                ofcRequest.setImsLogId(imsLogId);
			}
			
			ofcRequest.setExecuter(UserType.Officer);
			ofcRequest.setStatus(RequestStatus.Approved);
			ofcRequest.setOfficerId(officerId);
			ofcRequest.setProcessingDate(new Date());

			OFCRequestHistory history = new OFCRequestHistory();
			workflowDelegate.getMapper().map(ofcRequest, history);
			ofcRequest.getOfcHistory().add(history);
			
			boolean requestManipulated=workflowDelegate.manipulateRequest(ofcRequest,officerId, true, RequestAction.Approve);
			
			if(requestManipulated){
				sendTarakheesMail(paymentInfo, ofcRequest, request);
			}
			else
			{
				WorkFlowException workflowExp=new WorkFlowException("Error happened during Request Manipulation");
				workflowExp.setErrorCode("error.workflow.unexpected");
				throw workflowExp;
			}
		} catch (DataAccessException e){
			log.error("Officer.approveRequest() - DataAccessException going to send request to queue to be updated later",e);
			producer.generatePendingRequestMessage(ofcRequest);
			errors.reject("error.request");
		}catch(FNPServiceExpcetion fnpExp)
		{
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			errors.reject(fnpExp.getErrorCode());
			throw fnpExp;
		}
		catch (IMSException imsExp) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			
			
			imsExp.setErrorRollbackBean(UtilCommon.prepareRollback(null,  paymentInfo.getPaymentAdviceNumber(), txnNumber, customerUserName, imsLogId));
			errors.reject(imsExp.getErrorCode(),imsExp.getErrorArgs(),null);
			UtilCommon.rollbackTransaction();
			throw imsExp;
		}
		catch (WorkFlowException wfExp)
		{
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);

			wfExp.setErrorRollbackBean(UtilCommon.prepareRollback(null,  paymentInfo.getPaymentAdviceNumber(), txnNumber, customerUserName, imsLogId));
			errors.reject(wfExp.getErrorCode());
			UtilCommon.rollbackTransaction();
			throw wfExp;
		}
		catch (CommunicationException commExp) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);

			commExp.setErrorRollbackBean(UtilCommon.prepareRollback(null,  paymentInfo.getPaymentAdviceNumber(), txnNumber, customerUserName, imsLogId));
			errors.reject(commExp.getErrorCode());
			UtilCommon.rollbackTransaction();
			throw commExp;
		}
		catch (WebServiceException e){
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.approveRequest() - WebServiceException error occurred while approve request",e);
			errors.reject("error.generic");
			UtilCommon.rollbackTransaction();
		} catch (Exception e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.approveRequest() - Exception error occurred while approve request",e);
			errors.reject("error.generic");
			UtilCommon.rollbackTransaction();
		}
			
		//return "redirect:viewInbox.htm?type=inbox";
		return "redirect:listRequests.htm?type=myRequests";
	}


	private void sendTarakheesMail(PaymentAdvice paymentInfo,OFCRequest ofcRequest,HttpServletRequest request){
		File invoice=null;
		try {
			InputStream stream=new ByteArrayInputStream(paymentInfo.getFile());
			invoice=new File(generalMap.get("documentLocation")+"/"+paymentInfo.getPaymentAdviceNumber()+".pdf");
			
			FileOutputStream fos = new FileOutputStream(invoice);

			int data; 
			while((data=stream.read())!=-1)
			{ 
				char ch = (char)data;
				fos.write(ch);
			}
			fos.flush();
			fos.close();
	
			Map<String,String> parameters=new HashMap<String,String>();
			parameters.put(GlobalConstants.USERNAME,ofcRequest.getUserId());
			parameters.put(GlobalConstants.CUSTOMER_COMPANY,ofcRequest.getCompanyNameEnglish());
			parameters.put(GlobalConstants.REQUEST_TYPE,ofcRequest.getType().name());
			SimpleDateFormat fromatter=new SimpleDateFormat("dd/MM/yyyy");
			parameters.put(GlobalConstants.CREATION_DATE, fromatter.format(ofcRequest.getCreationDate()));
			parameters.put(GlobalConstants.SERVICE_FRIENDLY_NAME, UtilCommon.getFormmattedRequestId(ofcRequest.getService().getName(), ofcRequest.getType().name(), ofcRequest.getId(), ofcRequest.getCreationDate()));
			parameters.put(GlobalConstants.PAYMENT_ADVICE_NUMBER,paymentInfo.getPaymentAdviceNumber());
			parameters.put(GlobalConstants.PAYMENT_FEES,new DecimalFormat(GlobalConstants.FEES_FORMAT).format(paymentInfo.getPaymentfees()));
			
			if(null!=ofcRequest.getMainEmail() && !ofcRequest.getMainEmail().isEmpty())
			{
				mailUtility.sendMail(ofcRequest.getMainEmail() ,parameters ,invoice,GlobalConstants.FNP_TEMPLATE);
			}
			
			if(null!=ofcRequest.getAlternativeEmail() && !ofcRequest.getAlternativeEmail().isEmpty())
			{
				mailUtility.sendMail(ofcRequest.getAlternativeEmail(),  parameters,invoice,GlobalConstants.FNP_TEMPLATE);
			}
			
			if(null!=ofcRequest.getOptionalMail() && !ofcRequest.getOptionalMail().isEmpty())
			{
				mailUtility.sendMail(ofcRequest.getOptionalMail(),  parameters,invoice,GlobalConstants.FNP_TEMPLATE);
			}
			
			boolean deleted=invoice.delete();
			log.debug("Is file "+invoice.getAbsolutePath() + "Deleted: "+deleted) ;
			
		} catch (FileNotFoundException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.sendTarakheesMail() - error occurred while creating mail file : "+invoice.getPath(),e);
		} catch (IOException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.sendTarakheesMail() - error occurred while handling mail file : "+invoice.getPath() ,e);
		} catch (SystemException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.sendTarakheesMail() - error occurred while sending mail ",e);
		}	
}

	public PaymentAdvice generateFees(FNP fnpModel,String dbRequestId,String userName,String txnNumber,UserDetailVO userDetails)throws CommunicationException,FNPServiceExpcetion {
		
		PaymentAdvice paymentAdvice=null;
		String remarks="";
		
		if(null!=fnpModel.getRemarks())
		{
			remarks=fnpModel.getRemarks();
		}
		fnpModel.setRemarks("(RequestId: "+remarks);
		paymentAdvice = fnpDelegate.generatePaymentAdvice(fnpModel,userName,txnNumber,userDetails);

		return paymentAdvice;
	}



	@Transactional(readOnly = true)
	@RequestMapping(value = "/viewInbox.htm", method = RequestMethod.GET)
	public String viewInbox(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {

		model = setupActiveTasksForm(model, request, type, true);
		return "officer.viewInbox";
	}

	@RequestMapping(value = "/viewInbox.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String viewInbox(
			@ModelAttribute(value = GlobalConstants.REQUEST_SEARCH_CRITERIA) @Valid RequestSearchCriteria searchCriteria,
			BindingResult errors, Model model, HttpServletRequest request) {

		searchCriteria = buildRequestId(searchCriteria);
		if (errors.hasErrors()) {
			return "officer.listRequests";
		}
		model = submitActiveTasks(model, searchCriteria, request, true);
		return "officer.viewInbox";
	}

	// this method return details for both "my requests" and "My inbox"
	@Transactional(readOnly=true)
	@RequestMapping(value = "/viewDetails.htm", method = RequestMethod.GET)
	public String getRequestDetails(Model model,
			@RequestParam(value = "requestId") long requestId, HttpServletRequest request) {

		System.out
				.println("inside the get details method in Officer controller! and requestId = "
						+ requestId);
		OFCRequest ofcRequest = null;
		try {
			// 1- check if valid officerID, assuming that the officerId is
			// available session.
			
			String officerId=request.getUserPrincipal().getName();
			/*if (!workflowDelegate.isValidOfficer(officerId)) {
				// return error message to user
				String msg = "";
				return new ModelMap("", msg);
			}*/
			// 2- get the Details
			ofcRequest = workflowDelegate.getDetails(requestId, officerId,true);

			//if (ofcRequest == null) {
			// No need to check on the ofcRequest since the workflowDelegate 
			// re-throws an exception when this object is set to null internally
			//}
          	OFCRequestCreation ofcRequestModel = new OFCRequestCreation();
		workflowDelegate.getMapper().map(ofcRequest, ofcRequestModel);

		if (ofcRequestModel.getType().equals(RequestType.Amendment)) {
			ofcRequestModel.setAmendmentTypes(AmendmentType.values());
		}
		// TODO: return the model object
		ofcRequestModel.setOfficerComments("");
		ofcRequestModel.setServiceName(ofcRequest.getService().getName());
		model.addAttribute(GlobalConstants.OFC_REQUEST_MODEL, ofcRequestModel);
		return "officer.viewDetails";
		}
		catch (InvalidInputException invalExp) {
			
			ExceptionHandlerHelper.handleException(invalExp);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage(invalExp.getErrorCode(), null, RequestContextUtils.getLocale(request)));
			return "redirect:listRequests.htm?type=myRequests";
		}
		catch (Exception ex) {
			log.error("Officer.getRequestDetails()/GET - error while getting request ("+requestId+") details",ex);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("error.generic", null, RequestContextUtils.getLocale(request)));
			return "redirect:listRequests.htm?type=myRequests";
		}
	}

	@Transactional
	@RequestMapping(value = "/cancel.htm", method = RequestMethod.GET)
	public String cancelRequest(
			@RequestParam(value = GlobalConstants.REQUEST_ID) String requestId,
			HttpServletRequest request,
			@RequestHeader(value = "referer", required = false) String referer) {

		String officerId=request.getUserPrincipal().getName();
		try {
			workflowDelegate.cancelRequest(Long.parseLong(requestId),
					officerId, true);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.cancel", null, RequestContextUtils.getLocale(request)));
		} catch (NumberFormatException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.cancelRequest() - number formatting error while parsing request ("+requestId+")",e);
		} catch (InvalidInputException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.cancelRequest() - invalid input provided while cancel request ("+requestId+")",e);
		} catch (CommunicationException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.cancelRequest() - communication exception-work flow error while canceling request ("+requestId+")",e);
			UtilCommon.rollbackTransaction();
		}
		catch (FNPServiceExpcetion e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			ExceptionHandlerHelper.handleException(e);
			log.error("Officer.cancelRequest() - FNP error occurred while cancel request ("+requestId+")",e);
		}
		catch (IMSException e) {
			UtilCommon.rollbackTransaction();
			//ExceptionHandlerHelper.handleException(e);
			log.error("Officer.cancelRequest() - IMS error occurred while cancel request ("+requestId+")",e);
		}
		if(referer == null){
			referer = "listRequests.htm?type=" + request.getParameter("type");
		}else if(referer != null && !referer.contains("type")){
			referer = referer.concat("?type=" + request.getParameter("type"));
		}
		return "redirect:" + referer;
	}

	@Transactional
	@RequestMapping(value = "/close.htm", method = RequestMethod.GET)
	public String closeRequest(
			@RequestParam(value = GlobalConstants.REQUEST_ID) String requestId,
			HttpServletRequest request,
			@RequestHeader(value = "referer", required = false) String referer) {
		// TODO
		// integration with TSC
		String officerId=request.getUserPrincipal().getName();
		try {
			workflowDelegate.closeRequest(Long.parseLong(requestId), officerId,
					true);
			request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.close", null, RequestContextUtils.getLocale(request)));
		} catch (NumberFormatException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.closeRequest() - number formatting error while parsing request ("+requestId+")",e);
		} catch (InvalidInputException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.closeRequest() - invalid input provided while closing request ("+requestId+")",e);
		} catch (CommunicationException e) {
			UtilCommon.rollbackTransaction();
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			log.error("Officer.closeRequest() - communication exception - work flow error while closing request ("+requestId+")",e);
		} catch (FNPServiceExpcetion e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			UtilCommon.rollbackTransaction();
			log.error("Officer.closeRequest() - FNP error occurred while cancel request ("+requestId+")",e);
		} catch (IMSException e) {
			request.getSession().removeAttribute(GlobalConstants.SUCCESS_PARAM);
			UtilCommon.rollbackTransaction();
			//ExceptionHandlerHelper.handleException(e);
			log.error("Officer.closeRequest() - IMS error occurred while cancel request ("+requestId+")",e);
		}
		if(referer == null){
			referer = "listRequests.htm?type=" + request.getParameter("type");
		} else if (!referer.contains("type")){
			referer = referer.concat("?type=" + request.getParameter("type"));
		}
		return "redirect:" + referer;
	}

	

	@RequestMapping(value = "/unassignedRequests.htm", method = RequestMethod.GET)
	@Transactional(readOnly = true)
	public String unassignedRequests(Model model, HttpServletRequest request,
			@RequestParam(value = "type") String type) {

		model = setupActiveTasksForm(model, request, type, false);
		return "officer.unassignedRequests";
	}

	@RequestMapping(value = "/unassignedRequests.htm", method = RequestMethod.POST)
	@Transactional(readOnly = true)
	public String unassignedRequests(
			@ModelAttribute(value = GlobalConstants.REQUEST_SEARCH_CRITERIA) @Valid RequestSearchCriteria searchCriteria,
			BindingResult errors, Model model, HttpServletRequest request) {

		searchCriteria = buildRequestId(searchCriteria);
		if (errors.hasErrors()) {
			return "officer.unassignedRequests";
		}
		model = submitActiveTasks(model, searchCriteria, request, false);

		return "officer.unassignedRequests";
	}

	// Post method for getting active and unassigned tasks
	private Model submitActiveTasks(Model model,
			RequestSearchCriteria searchCriteria, HttpServletRequest request,
			boolean isAssigned) {
		/*String userId = "somaya.rayan";// should get it from session
												// when integrating with login
												// logic,but now for testing we
												// will add it here
		HttpSession session = request.getSession();
		session.setAttribute(GlobalConstants.USER_NAME_ATTRIBUTE, userId);*/
		// session.setAttribute(GlobalConstants.TYPE_ATTRIBUTE,
		// GlobalConstants.MY_REQUESTS);
		String officerId=request.getUserPrincipal().getName();

		System.out
				.println("**************** Officer controller ,listRequests, POST");
		List<Request> requests = new ArrayList<Request>();
		try {
			long getAllActiveTasksSize = 0;
			getAllActiveTasksSize = workflowDelegate.getAllActiveTasksSize(
					WorkflowDataFields.ProcessName.getPropertyName(), officerId,
					true, searchCriteria, isAssigned);

			System.out.println("*** getAllActiveTasksSize = "
					+ getAllActiveTasksSize + " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = getAllActiveTasksSize / pageSize;
			if ((getAllActiveTasksSize % pageSize) > 0) {
				totalPages++;
			}
			System.out.println("*** totalPages = " + totalPages + " ******");
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) getAllActiveTasksSize);
			searchCriteria.setFirstAndLastPageFlags();
			requests = workflowDelegate.getActiveTasks(searchCriteria,
					WorkflowDataFields.ProcessName.getPropertyName(), officerId,
					true, isAssigned);
			System.out.println("requests retuned = " + requests.size());
		} catch (Exception e) {
			log.error("Officer.submitActiveTasks() - error occurred while submitting active tasks",e);
		}
		if(isAssigned){
			searchCriteria.setStatuses(searchCriteria.getOfficerStatuses());
		}else{
			List<RequestStatus> statuses = new ArrayList<RequestStatus>();
			statuses.add(RequestStatus.Submitted);
			searchCriteria.setStatuses(statuses);
		}
		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return model;
	}

	// Get method for getting active and unassigned tasks
	private Model setupActiveTasksForm(Model model, HttpServletRequest request,
			String type, boolean isAssigned) {
		/*String userId = "somaya.rayan";// should get it from session
												// when integrating with login
												// logic,but now for testing we
												// will add it here
		HttpSession session = request.getSession();
		session.setAttribute(GlobalConstants.USER_NAME_ATTRIBUTE, userId);*/
		// session.setAttribute(GlobalConstants.TYPE_ATTRIBUTE,
		// GlobalConstants.MY_REQUESTS);
		String officerId=request.getUserPrincipal().getName();
		System.out
				.println("inside the viewInbox GET method in Officer controller ");

		// 1- set the default date period
		RequestSearchCriteria searchCriteria = new RequestSearchCriteria();

		Calendar today = Calendar.getInstance();
		today.setTime(new Date());
		searchCriteria.setPageNumber(1);
		// this attribue is added to keep track of which menu item is currently
		// selected!!!!
		searchCriteria.setType(type);

		List<Request> requests = new ArrayList<Request>();
		try {
			long getAllActiveTasksSize = 0;
			getAllActiveTasksSize = workflowDelegate.getAllActiveTasksSize(
					WorkflowDataFields.ProcessName.getPropertyName(), officerId,
					true, searchCriteria, isAssigned);

			System.out.println("*** getAllActiveTasksSize = "
					+ getAllActiveTasksSize + " ******");
			long pageSize = Long.parseLong(generalMap.get("pageSize"));
			long totalPages = getAllActiveTasksSize / pageSize;
			if ((getAllActiveTasksSize % pageSize) > 0) {
				totalPages++;
			}
			searchCriteria.setTotalPageNumber((int) totalPages);
			searchCriteria.setTotalResultSize((int) getAllActiveTasksSize);
			searchCriteria.setFirstAndLastPageFlags();
			searchCriteria.setAssending(true);
			System.out.println("*** totalPages = " + totalPages + " ******");
			requests = workflowDelegate.getActiveTasks(searchCriteria,
					WorkflowDataFields.ProcessName.getPropertyName(), officerId,
					true, isAssigned);
			searchCriteria.setSortField(RequestField.CreationDate.getPropertyName());
		} catch (Exception ex) {
			log.error("Officer.setupActiveTasksForm() - error occurred while setup active tasks form",ex);
		}
		if(isAssigned){
			searchCriteria.setStatuses(searchCriteria.getOfficerStatuses());
		}else{
			List<RequestStatus> statuses = new ArrayList<RequestStatus>();
			statuses.add(RequestStatus.Submitted);
			searchCriteria.setStatuses(statuses);
		}

		model.addAttribute(GlobalConstants.REQUEST_SEARCH_CRITERIA,
				searchCriteria);
		model.addAttribute("requests", requests);
		return model;
	}

	private RequestSearchCriteria buildRequestId(
			RequestSearchCriteria searchCriteria) {
		if (null != searchCriteria) {
			String viewReqId = searchCriteria.getViewRequestId();
			if (null != viewReqId) {
				String[] requestIdData = viewReqId.split("_");
				searchCriteria.setServiceName(requestIdData[0] + "_" + requestIdData[1].trim());
				searchCriteria.setRequestType(requestIdData[2]);
				searchCriteria.setCreationDate(UtilCommon
						.getDateFromString(requestIdData[3]));
				searchCriteria.setRequestId(Long.parseLong(requestIdData[4]));
			}
		}
		return searchCriteria;
	}

	@Transactional
	private boolean confirmPayment(OFCRequestCreation ofcRequestModel,String officerId, HttpServletRequest request)
			throws CommunicationException, InvalidInputException, WorkFlowException,
			RuntimeException, FNPServiceExpcetion {
		OFCRequest ofcRequest = new OFCRequest();
		workflowDelegate.getMapper().map(ofcRequestModel, ofcRequest);
		String paymentAdviceNumber = "";
		if (ofcRequest.getStatus()
				.equals(RequestStatus.Payment_Done)) {
			paymentAdviceNumber = ofcRequest.getFnpList().get(0)
					.getPaymentNumber();
			if (fnpDelegate.queryPaymentAdviceStatus(paymentAdviceNumber).toUpperCase()
					.equals(FNPRequestStatus.PAYMENT_CONFIRMED.getStatusName().toUpperCase())) {
				ofcRequest = updateRequest(ofcRequest,
						RequestStatus.Payment_Confirmed,officerId);
				boolean requestManipulated=workflowDelegate.manipulateRequest(ofcRequest, ofcRequest.getOfficerId(), true, RequestAction.PaymentConfirmed);
				if(!requestManipulated)
				{
					WorkFlowException workflowExp=new WorkFlowException("Error happened during Request Manipulation");
					workflowExp.setErrorCode("error.workflow.unexpected");
					throw workflowExp;
				}
				return true;
			} else {
				return false;
			}
		} else if (ofcRequest.getStatus().equals(RequestStatus.Additional_Payment_Done)) {
			paymentAdviceNumber = ofcRequest.getFnpList().get(1)
					.getPaymentNumber();
			if (fnpDelegate.queryPaymentAdviceStatus(paymentAdviceNumber)
					.equals(FNPRequestStatus.PAYMENT_CONFIRMED.getStatusName())) {
				ofcRequest = updateRequest(ofcRequest,
						RequestStatus.Closed,officerId);
                                 //TODO
				//Change it after discussion with EZZ
				boolean requestManipulated=workflowDelegate.manipulateRequest(ofcRequest, ofcRequest.getOfficerId(), true, RequestAction.ADDITIONAL_Payment_Confirmed);
				//request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage("success.request.info.edit", null, RequestContextUtils.getLocale(request)));
				if(!requestManipulated)
				{
					WorkFlowException workflowExp=new WorkFlowException("Error happened during Request Manipulation");
					workflowExp.setErrorCode("error.workflow.unexpected");
					throw workflowExp;
				}
				return true;
			} else {
				return false;
			}
		}
		return false;

	}

	
	private OFCRequest updateRequest(OFCRequest ofcRequest,
			RequestStatus requestStatus,String officerId) {
		// TODO
		// After authantication, we must replace this with logged in user
		ofcRequest.setStatus(requestStatus);
		ofcRequest.setOfficerId(officerId);
		ofcRequest.setExecuter(UserType.Officer);
		ofcRequest.setProcessingDate(new Date());

		OFCRequestHistory history = new OFCRequestHistory();
		workflowDelegate.getMapper().map(ofcRequest, history);

		ofcRequest.getOfcHistory().add(history);

		return ofcRequest;
	}

	
	@Transactional
	private String returnOrReject(OFCRequestCreation ofcRequestModel,
			BindingResult errors, RequestAction requestAction, String referer,String officerId, HttpServletRequest request)
			throws InvalidInputException, WorkFlowException, RuntimeException {
		if (null == ofcRequestModel.getOfficerComments()
				|| ofcRequestModel.getOfficerComments().isEmpty()) {
			errors.reject("error.ofcRequestModel.officerComments");
		}

		if (errors.hasErrors()) {
			return "redirect:" + referer;
		}
		OFCRequest ofcRequest = new OFCRequest();
		
		String successMessage = "success.request.info.edit";
		// TODO
		// After authantication, we must replace this with logged in user
		boolean isReturnedForUpdate = false;
		workflowDelegate.getMapper().map(ofcRequestModel, ofcRequest);
		try {
		if (requestAction.equals(RequestAction.ReturnForUpdate)) {
			ofcRequest = updateRequest(ofcRequest,
					RequestStatus.Return_For_Update,officerId);
                        isReturnedForUpdate = workflowDelegate.manipulateRequest(
					ofcRequest, officerId, true, RequestAction.ReturnForUpdate);
		} else if (requestAction.equals(RequestAction.Reject)) {
			ofcRequest = updateRequest(ofcRequest, RequestStatus.Rejected,officerId);
			isReturnedForUpdate = workflowDelegate.manipulateRequest(
					ofcRequest, officerId, true, RequestAction.Reject);
		}
			if (isReturnedForUpdate) {
				request.getSession().setAttribute(GlobalConstants.SUCCESS_PARAM, messageSource.getMessage(successMessage, null, RequestContextUtils.getLocale(request)));
				//return "redirect:viewInbox.htm?type=inbox";
				return "redirect:listRequests.htm?type=myRequests";
			} else {
				errors.reject("error.workflow.unexpected");
				return "redirect:" + referer;
			}

		} catch (InvalidInputException e) {
			errors.reject("error.ofcRequestModel.exception");
			return "redirect:" + referer;
		} catch (CommunicationException e) {
			ExceptionHandlerHelper.handleException(e);
			errors.reject("error.ofcRequestModel.exception");
			return "redirect:" + referer;
		}
	}
}
